//
// Created on 2024/6/26.
//
/*
# Copyright (c) 2024 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
*/

#include "ohos_egl_context_manager.h"
#include "rtc_base/internal/default_socket_server.h"
#include "rtc_base/logging.h"

namespace webrtc {

OhosEGLContextManager OhosEGLContextManager::ohosEGLContextManage_;

std::shared_ptr<EGLContextResource> OhosEGLContextManager::GetEGLContextResource() {
    std::lock_guard<std::mutex> lock(mutex_);
    if (!root_gl_resource_) {
        auto eglContext = std::make_shared<EGLRenderContext>();
        if (!eglContext->Init()) {
            return nullptr;
        }
        root_gl_resource_ = std::make_shared<EGLContextResource>(eglContext);
    }
    return root_gl_resource_;
}

std::shared_ptr<std::mutex> OhosEGLContextManager::GetTextureMutex(GLuint texture_id) {
    std::lock_guard<std::mutex> lock(texture_mutex_map_mutex_);
    auto item = texture_mutex_map_.find(texture_id);
    if (item != texture_mutex_map_.end()) {
        return item->second;
    } else {
        auto mutex_ptr = std::make_shared<std::mutex>();
        texture_mutex_map_[texture_id] = mutex_ptr;
        return mutex_ptr;
    }
}

std::shared_ptr<YuvConverter> OhosEGLContextManager::GetYuvConverter() {
    std::lock_guard<std::mutex> lock(yuv_converter_mutex_);
    if (!yuv_converter_) {
        converter_gl_context_ = std::make_unique<EGLRenderContext>();
        if (!converter_gl_context_->Init(root_gl_resource_->eglContext_->GetEGLContext())) {
            RTC_LOG_T(LS_ERROR) << "Failed to init EGL context!";
            return nullptr;
        }
        EGLint pBufferAttributes[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
        egl_surface_ = converter_gl_context_->CreatePBufferEglSurface(pBufferAttributes);
        if (egl_surface_ == EGL_NO_SURFACE) {
            RTC_LOG_T(LS_ERROR) << "Failed to create EGL surface!";
            return nullptr;
        }
        convert_thread_ = new rtc::Thread(rtc::CreateDefaultSocketServer());
        convert_thread_->SetName("yuv_convert_thread", nullptr);
        convert_thread_->Start();
        yuv_converter_ = std::make_shared<YuvConverter>();
        yuv_converter_->SetConvertThread(convert_thread_);
        convert_thread_->BlockingCall([this](){
            converter_gl_context_->MakeCurrent(egl_surface_);
            yuv_converter_->Init();
        });
    }
    return yuv_converter_;
}

void OhosEGLContextManager::Clear() {
    {
        std::lock_guard<std::mutex> lock(mutex_);
        root_gl_resource_.reset();
    }
    {
        std::lock_guard<std::mutex> lock(texture_mutex_map_mutex_);
        texture_mutex_map_.clear();
    }
    {
        std::lock_guard<std::mutex> lock(yuv_converter_mutex_);
        if (convert_thread_ && yuv_converter_) {
            convert_thread_->BlockingCall([this](){
                yuv_converter_->Clear();
            });
        }
        if (converter_gl_context_ && egl_surface_ != EGL_NO_SURFACE) {
            converter_gl_context_->DestroyEglSurface(egl_surface_);
            egl_surface_ = EGL_NO_SURFACE;
        }
        converter_gl_context_.reset();
        yuv_converter_.reset();
        if (convert_thread_) {
            convert_thread_->Stop();
            delete convert_thread_;
            convert_thread_ = nullptr;
        }
    }
}

} // namespace webrtc